#ifndef _INTERFACE_CONSOLE_FRACTION_MENU_
#define _INTERFACE_CONSOLE_FRACTION_MENU_

#include "..\..\mathematics\algebra\fraction.h"
using namespace science::mathematics::algebra;

#include <memory>
#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;

#include "console_settings.h"

namespace science
{
	namespace interface
	{
		namespace console
		{
			enum class FRACTION_MENU_OPTIONS
			{
				OPTION_FRACTION_EQUALITY,
				OPTION_FRACTION_ADDITION,
				OPTION_FRACTION_SUBTRACTION,
				OPTION_FRACTION_MULTIPLICATION,
				OPTION_FRACTION_DIVISION,
				OPTION_FRACTION_SIMPLIFICATION,
				OPTION_FRACTION_SAVING,
				OPTION_FRACTION_CLEAR_MEMORY,
				OPTION_FRACTION_EXIT,
				OPTION_FRACTION_UNKNOWN
			};

			class fraction_menu
			{
			private:

				static std::shared_ptr<fraction> _saved_fraction;

			public:
				static FRACTION_MENU_OPTIONS show_menu()
				{
					console_settings::clear_screen();

					cout << "Choose option from the next menu:" << endl;
					cout << "  1 - fraction = fraction?." << endl;
					cout << "  2 - fraction + fraction." << endl;
					cout << "  3 - fraction - fraction." << endl;
					cout << "  4 - fraction * fraction." << endl;
					cout << "  5 - fraction / fraction." << endl;
					cout << "  6 - simplify fraction." << endl;
					cout << "  7 - save fraction in memory." << endl;
					cout << "  8 - clear memory." << endl;
					cout << "  9 - Exit program." << endl << endl;

					int option = console_settings::get_int_option("Your option? ");

					switch (option)
					{
					case 1:
						return FRACTION_MENU_OPTIONS::OPTION_FRACTION_EQUALITY;
					case 2:
						return FRACTION_MENU_OPTIONS::OPTION_FRACTION_ADDITION;
					case 3:
						return FRACTION_MENU_OPTIONS::OPTION_FRACTION_SUBTRACTION;
					case 4:
						return FRACTION_MENU_OPTIONS::OPTION_FRACTION_MULTIPLICATION;
					case 5:
						return FRACTION_MENU_OPTIONS::OPTION_FRACTION_DIVISION;
					case 6:
						return FRACTION_MENU_OPTIONS::OPTION_FRACTION_SIMPLIFICATION;
					case 7:
						return FRACTION_MENU_OPTIONS::OPTION_FRACTION_SAVING;
					case 8:
						return FRACTION_MENU_OPTIONS::OPTION_FRACTION_CLEAR_MEMORY;
					case 9:
						return FRACTION_MENU_OPTIONS::OPTION_FRACTION_EXIT;
					default:
						return FRACTION_MENU_OPTIONS::OPTION_FRACTION_UNKNOWN;
					}
				}

				static void run()
				{
					while (true)
					{
						FRACTION_MENU_OPTIONS option = fraction_menu::show_menu();
						switch (option)
						{
						case science::interface::console::FRACTION_MENU_OPTIONS::OPTION_FRACTION_EQUALITY:
							check_fraction_equality();
							break;
						case science::interface::console::FRACTION_MENU_OPTIONS::OPTION_FRACTION_ADDITION:
							add_two_fractions();
							break;
						case science::interface::console::FRACTION_MENU_OPTIONS::OPTION_FRACTION_SUBTRACTION:
							subtract_two_fractions();
							break;
						case science::interface::console::FRACTION_MENU_OPTIONS::OPTION_FRACTION_MULTIPLICATION:
							multiply_two_fractions();
							break;
						case science::interface::console::FRACTION_MENU_OPTIONS::OPTION_FRACTION_DIVISION:
							divide_two_fractions();
							break;
						case science::interface::console::FRACTION_MENU_OPTIONS::OPTION_FRACTION_SIMPLIFICATION:
							simplify_fraction();
							break;
						case science::interface::console::FRACTION_MENU_OPTIONS::OPTION_FRACTION_SAVING:
							save_fraction_in_memory();
							break;
						case science::interface::console::FRACTION_MENU_OPTIONS::OPTION_FRACTION_CLEAR_MEMORY:
							_saved_fraction = nullptr;
							break;
						case science::interface::console::FRACTION_MENU_OPTIONS::OPTION_FRACTION_EXIT:
							return;
						case science::interface::console::FRACTION_MENU_OPTIONS::OPTION_FRACTION_UNKNOWN:
							cout << endl << "Invalid option, please choose again.." << endl;
							break;
						default:
							break;
						}					
					};
				}

			public:

				static bool load_from_memory()
				{
					if (_saved_fraction == nullptr)
						return false;

					char option = console_settings::get_char_option("Do you want so load the saved fraction? ");
					if (option == 'Y' || option == 'y')
					{
						cout << "The loaded fraction is : " << *(_saved_fraction.get()) << endl;
						return true;
					}
					else
						return false;
				}				

				static void load_two_fraction(fraction& frc1, fraction& frc2)
				{					
					if (load_from_memory())
						frc1 = *(_saved_fraction.get());
					else
						frc1 = console_settings::get_from_user<fraction>("Enter first fraction : ");

					frc2 = console_settings::get_from_user<fraction>("Enter second fraction : ");
				}

				static fraction load_one_fraction()
				{
					if (load_from_memory())
						return *(_saved_fraction.get());
					else
						return console_settings::get_from_user<fraction>("Enter fraction : ");
				}

				static void check_fraction_equality()
				{
					fraction frc1, frc2;

					console_settings::clear_screen();
					load_two_fraction(frc1, frc2);

					if (frc1 == frc2)
						cout << "The two fractions : " << frc1 << " and " << frc2 << " are equals." << endl;
					else
						cout << "The two fractions : " << frc1 << " and " << frc2 << " are not equals." << endl;

					if (console_settings::do_again())
						check_fraction_equality();
				}

				static void add_two_fractions()
				{
					fraction frc1, frc2;

					console_settings::clear_screen();
					load_two_fraction(frc1, frc2);

					fraction result = frc1 + frc2;
					cout << frc1 << " + " << frc2 << " = " << result << endl;
					save_result_in_memory(result);

					if (console_settings::do_again())
						add_two_fractions();
				}

				static void subtract_two_fractions()
				{
					fraction frc1, frc2;

					console_settings::clear_screen();
					load_two_fraction(frc1, frc2);

					fraction result = frc1 - frc2;
					cout << frc1 << " - " << frc2 << " = " << result << endl;
					save_result_in_memory(result);

					if (console_settings::do_again())
						subtract_two_fractions();
				}

				static void multiply_two_fractions()
				{
					fraction frc1, frc2;

					console_settings::clear_screen();
					load_two_fraction(frc1, frc2);

					fraction result = frc1 * frc2;
					cout << frc1 << " * " << frc2 << " = " << result << endl;
					save_result_in_memory(result);

					if (console_settings::do_again())
						multiply_two_fractions();
				}

				static void divide_two_fractions()
				{
					fraction frc1, frc2;

					console_settings::clear_screen();
					load_two_fraction(frc1, frc2);

					fraction result = frc1 / frc2;
					cout << frc1 << " / " << frc2 << " = " << result << endl;
					save_result_in_memory(result);

					if (console_settings::do_again())
						divide_two_fractions();
				}

				static void simplify_fraction()
				{
					console_settings::clear_screen();
					fraction frc = load_one_fraction();					

					fraction result = frc.simplify();
					cout << "Simplifying : " << frc << " becomes " << result << endl;
					save_result_in_memory(result);

					if (console_settings::do_again())
						simplify_fraction();
				}

				static void save_result_in_memory(fraction frc)
				{
					if (console_settings::do_again("Save the result to memory? "))
					{
						_saved_fraction = std::shared_ptr<fraction>(new fraction());
						*_saved_fraction = frc;
					}
				}

				static void save_fraction_in_memory()
				{
					console_settings::clear_screen();
					fraction frc = console_settings::get_from_user<fraction>("Enter fraction : ");
					_saved_fraction = std::shared_ptr<fraction>(new fraction());
					*_saved_fraction = frc;
					cout << "Fraction saved." << endl;
				}
			};

			std::shared_ptr<fraction> fraction_menu::_saved_fraction = nullptr;
		}
	}
}

#endif